﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace ImageProcessing
{
	class SpecialEffects
	{
		public static Bitmap Pixelation(Bitmap bmIn, int tn, int rn, bool doPolar)
		{
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height, bmIn.PixelFormat);
			int k;
			double td;
			int rows = bmIn.Height;
			int cols = bmIn.Width;
			int xShift = cols / 2;
			int yShift = rows / 2;
			int x1, y1, x, y, x2, y2;
			double r, t;
			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectSrc, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			if (doPolar)
			{
				td = (tn * Math.PI) / 180.0;

				unsafe
				{
					byte* sptr = (byte*)(void*)srcPtr;
					byte* dptr = (byte*)(void*)destPtr;

					for (int j = 0; j < rows; j++)
					{
						k = j * srcStride;
						for (int i = 0; i < cols; i++)
						{
							x = i;
							y = j;
							x1 = x - xShift;
							y1 = y - yShift;

							r = Math.Sqrt(x1 * x1 + y1 * y1);
							t = Math.Atan2(y1, x1);

							r = Math.Floor(r / rn) * rn;
							t = Math.Floor(t / td) * td;

							x2 = (int)(Math.Round(r * Math.Cos(t)) + xShift);
							y2 = (int)(Math.Round(r * Math.Sin(t)) + yShift);

							if (x2 < 0) x2 = 0;
							if (x2 >= cols) x2 = cols - 1;
							if (y2 < 0) y2 = 0;
							if (y2 >= rows) y2 = rows - 1;

							dptr[k + i * srcBytePP] = sptr[y2 * srcStride + x2 * srcBytePP];
							if (srcBytePP > 1)
							{
								dptr[k + i * srcBytePP + 1] = sptr[y2 * srcStride + x2 * srcBytePP + 1];
								dptr[k + i * srcBytePP + 2] = sptr[y2 * srcStride + x2 * srcBytePP + 2];
								if (srcBytePP >= 4)
								{
									dptr[k + i * srcBytePP + 3] = 255;
								} //end if
							} //end if
						} //end for
					} //end for		
				} //end unsafe

				bmIn.UnlockBits(srcBitData);
				bmOut.UnlockBits(destBitData);

			} //end if
			else
			{
				unsafe
				{
					byte* sptr = (byte*)(void*)srcPtr;
					byte* dptr = (byte*)(void*)destPtr;
					for (int j = 0; j < bmOut.Height; j++)
					{
						k = j * srcStride;
						for (int i = 0; i < bmOut.Width; i++)
						{
							//choose same pixel for sizex and sizey pixels
							dptr[k + i * srcBytePP] = sptr[((j / rn) * rn) * srcStride + (i / tn) * tn * srcBytePP];
							if (srcBytePP > 1)
							{
								dptr[k + i * srcBytePP + 1] = sptr[(j / rn) * rn * srcStride + (i / tn) * tn * srcBytePP + 1];
								dptr[k + i * srcBytePP + 2] = sptr[(j / rn) * rn * srcStride + (i / tn) * tn * srcBytePP + 2];
							} //end if
							if (srcBytePP >= 4)
								dptr[k + i * srcBytePP + 3] = 255;

						} //end for
					} //end for
				} //end unsafe
				bmIn.UnlockBits(srcBitData);
				bmOut.UnlockBits(destBitData);
			} //end else


			return bmOut;

		}//end Pixelation

		public static Bitmap Ripple(Bitmap bmIn, int tn, int rn, bool doPolar)
		{
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height, bmIn.PixelFormat);
			int k;
			double td;
			int rows = bmIn.Height;
			int cols = bmIn.Width;
			int xShift = cols / 2;
			int yShift = rows / 2;
			int shiftJ, shiftI;
			int x1, y1, x, y, x2, y2;
			double r, t;
			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectSrc, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			if (doPolar)
			{
				//MessageBox.Show("not implemented yet");
				//bmIn.UnlockBits(srcBitData);
				//bmOut.UnlockBits(destBitData);
				//return bmIn;
				td = (tn * Math.PI) / 180.0;

				unsafe
				{
					byte* sptr = (byte*)(void*)srcPtr;
					byte* dptr = (byte*)(void*)destPtr;

					for (int j = 0; j < rows; j++)
					{
						k = j * srcStride;
						for (int i = 0; i < cols; i++)
						{
							x = i;
							y = j;

							//change origin
							x1 = x - xShift;
							y1 = y - yShift;

							//find polar coords
							r = Math.Sqrt(x1 * x1 + y1 * y1);
							t = Math.Atan2(y1, x1);

							//mod r and theta
							r = 2*r - Math.Floor(r / rn) * rn;
							t = 2*t - Math.Floor(t / td) * td;

							//find come from coords
							x2 = (int)(Math.Round(r * Math.Cos(t)) + xShift);
							y2 = (int)(Math.Round(r * Math.Sin(t)) + yShift);

							if (x2 < 0) x2 = 0;
							if (x2 >= cols) x2 = cols - 1;
							if (y2 < 0) y2 = 0;
							if (y2 >= rows) y2 = rows - 1;

							dptr[k + i * srcBytePP] = sptr[y2 * srcStride + x2 * srcBytePP];
							if (srcBytePP > 1)
							{
								dptr[k + i * srcBytePP + 1] = sptr[y2 * srcStride + x2 * srcBytePP + 1];
								dptr[k + i * srcBytePP + 2] = sptr[y2 * srcStride + x2 * srcBytePP + 2];
								if (srcBytePP >= 4)
								{
									dptr[k + i * srcBytePP + 3] = 255;
								} //end if
							} //end if
						} //end for
					} //end for		
				} //end unsafe

				bmIn.UnlockBits(srcBitData);
				bmOut.UnlockBits(destBitData);

			} //end if
			else
			{
				unsafe
				{
					byte* sptr = (byte*)(void*)srcPtr;
					byte* dptr = (byte*)(void*)destPtr;
					for (int j = 0; j < bmOut.Height; j++)
					{
						k = j * srcStride;
						for (int i = 0; i < bmOut.Width; i++)
						{
							//choose same pixel for sizex and sizey pixels
							if (rn == 0)
							{
								shiftJ = k;
							} //end if
							else
							{
								shiftJ = Math.Min((2 * j - j / rn * rn) * srcStride, (bmOut.Height - 1) * srcStride);
								//shiftJ = Math.Min((j + j % rn) * srcStride, (bmOut.Height - 1) * srcStride);
							}

							if (tn == 0)
							{
								shiftI = i * srcBytePP;
							} //end if
							else
							{
								shiftI = Math.Min((2 * i - i / tn * tn) * srcBytePP, (bmOut.Width - 1) * srcBytePP);
								//shiftI = Math.Min((i + i % tn) * srcBytePP, (bmOut.Width - 1) * srcBytePP);
							} //end else

							dptr[k + i * srcBytePP] = sptr[shiftI + shiftJ];
							if (srcBytePP > 1)
							{

								dptr[k + i * srcBytePP + 1] = sptr[shiftI + shiftJ + 1];
								dptr[k + i * srcBytePP + 2] = sptr[shiftI + shiftJ + 2];
							} //end if
							if (srcBytePP >= 4)
								dptr[k + i * srcBytePP + 3] = 255;

						} //end for
					} //end for
				} //end unsafe
				bmIn.UnlockBits(srcBitData);
				bmOut.UnlockBits(destBitData);
			} //end else


			return bmOut;

		}//end Ripple

		public static Bitmap Twirl(Bitmap bmIn, int nk)
		{
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height, bmIn.PixelFormat);
			int k;
			int rows = bmIn.Height;
			int cols = bmIn.Width;
			int xShift = cols / 2;
			int yShift = rows / 2;
			int x1, y1, x, y, x2, y2;
			double r, t;
			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectSrc, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				byte* dptr = (byte*)(void*)destPtr;

				for (int j = 0; j < rows; j++)
				{
					k = j * srcStride;
					for (int i = 0; i < cols; i++)
					{
						x = i;
						y = j;
						x1 = x - xShift;
						y1 = y - yShift;

						r = Math.Sqrt(x1 * x1 + y1 * y1);
						t = Math.Atan2(y1, x1) + r/nk;

						x2 = (int)(Math.Round(r * Math.Cos(t)) + xShift);
						y2 = (int)(Math.Round(r * Math.Sin(t)) + yShift);

						if (x2 < 0) x2 = 0;
						if (x2 >= cols) x2 = cols - 1;
						if (y2 < 0) y2 = 0;
						if (y2 >= rows) y2 = rows - 1;

						dptr[k + i * srcBytePP] = sptr[y2 * srcStride + x2 * srcBytePP];
						if (srcBytePP > 1)
						{
							dptr[k + i * srcBytePP + 1] = sptr[y2 * srcStride + x2 * srcBytePP + 1];
							dptr[k + i * srcBytePP + 2] = sptr[y2 * srcStride + x2 * srcBytePP + 2];
							if (srcBytePP >= 4)
							{
								dptr[k + i * srcBytePP + 3] = 255;
							} //end if
						} //end if
					} //end for
				} //end for		
			} //end unsafe

			bmIn.UnlockBits(srcBitData);
			bmOut.UnlockBits(destBitData);

			return bmOut;
		}//end Twirl

		public static Bitmap Jitter(Bitmap bmIn, int nk, int nn)
		{
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height, bmIn.PixelFormat);
			int k;
			int rows = bmIn.Height;
			int cols = bmIn.Width;
			int xShift = cols / 2;
			int yShift = rows / 2;
			int x1, y1, x, y, x2, y2;
			double r, t;
			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectSrc, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				byte* dptr = (byte*)(void*)destPtr;

				for (int j = 0; j < rows; j++)
				{
					k = j * srcStride;
					for (int i = 0; i < cols; i++)
					{
						x = i;
						y = j;
						x1 = x - xShift;
						y1 = y - yShift;

						r = Math.Sqrt(x1 * x1 + y1 * y1);
						t = Math.Atan2(y1, x1);
						t = t + (t % (nk*Math.PI/180.0)) - nn*Math.PI/180.0;


						x2 = (int)(Math.Round(r * Math.Cos(t)) + xShift);
						y2 = (int)(Math.Round(r * Math.Sin(t)) + yShift);

						if (x2 < 0) x2 = 0;
						if (x2 >= cols) x2 = cols - 1;
						if (y2 < 0) y2 = 0;
						if (y2 >= rows) y2 = rows - 1;

						dptr[k + i * srcBytePP] = sptr[y2 * srcStride + x2 * srcBytePP];
						if (srcBytePP > 1)
						{
							dptr[k + i * srcBytePP + 1] = sptr[y2 * srcStride + x2 * srcBytePP + 1];
							dptr[k + i * srcBytePP + 2] = sptr[y2 * srcStride + x2 * srcBytePP + 2];
							if (srcBytePP >= 4)
							{
								dptr[k + i * srcBytePP + 3] = 255;
							} //end if
						} //end if
					} //end for
				} //end for		
			} //end unsafe

			bmIn.UnlockBits(srcBitData);
			bmOut.UnlockBits(destBitData);

			return bmOut;
		}//end Jitter

		public static Bitmap CircularSlice(Bitmap bmIn, int nk)
		{
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height, bmIn.PixelFormat);
			int k;
			int rows = bmIn.Height;
			int cols = bmIn.Width;
			int xShift = cols / 2;
			int yShift = rows / 2;
			int x1, y1, x, y, x2, y2;
			double r, t;
			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectSrc, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				byte* dptr = (byte*)(void*)destPtr;

				for (int j = 0; j < rows; j++)
				{
					k = j * srcStride;
					for (int i = 0; i < cols; i++)
					{
						x = i;
						y = j;
						x1 = x - xShift;
						y1 = y - yShift;

						r = Math.Sqrt(x1 * x1 + y1 * y1);
						t = Math.Atan2(y1, x1);

						t += (r % nk) * Math.PI / 180;

						x2 = (int)(Math.Round(r * Math.Cos(t)) + xShift);
						y2 = (int)(Math.Round(r * Math.Sin(t)) + yShift);

						if (x2 < 0) x2 = 0;
						if (x2 >= cols) x2 = cols - 1;
						if (y2 < 0) y2 = 0;
						if (y2 >= rows) y2 = rows - 1;

						dptr[k + i * srcBytePP] = sptr[y2 * srcStride + x2 * srcBytePP];
						if (srcBytePP > 1)
						{
							dptr[k + i * srcBytePP + 1] = sptr[y2 * srcStride + x2 * srcBytePP + 1];
							dptr[k + i * srcBytePP + 2] = sptr[y2 * srcStride + x2 * srcBytePP + 2];
							if (srcBytePP >= 4)
							{
								dptr[k + i * srcBytePP + 3] = 255;
							} //end if
						} //end if
					} //end for
				} //end for		
			} //end unsafe

			bmIn.UnlockBits(srcBitData);
			bmOut.UnlockBits(destBitData);

			return bmOut;
		}//end CircularSlice

	}
}
